package com.abocode.aichat.server.context.handler;

import com.abocode.aichat.data.*;
import com.abocode.aichat.exception.NotReadyException;
import com.abocode.aichat.server.context.ServerRuntimeContext;
import com.abocode.aichat.server.context.worker.Worker;
import com.abocode.aichat.util.UUIDUtils;
import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


/**
 * @author guanxf
 */
@ChannelHandler.Sharable
public abstract class ServerInboundHandler extends SimpleChannelInboundHandler<String> {
    private static final String HEART_STR = " ";
    private static final Log log = LogFactory.getLog(ServerInboundHandler.class);
    protected ServerRuntimeContext serverRuntimeContext;
    public ServerInboundHandler(ServerRuntimeContext serverRuntimeContext) {
        if (serverRuntimeContext == null) {
            throw new NullPointerException("serverRuntimeContext is null");
        }
        this.serverRuntimeContext = serverRuntimeContext;
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,
                                Throwable cause) throws Exception {
        log.info("exceptionCaught" + cause.getMessage(), cause);
            ctx.channel().writeAndFlush(JSON.toJSONString(new MessageStanzaImpl(UUIDUtils.sn(), error(cause)))).sync();
            ctx.channel().close();
    }

    public MessageBody error(Throwable cause) {
        RespMessage body = new RespMessage();
        if (cause instanceof NotReadyException) {
            body.setCode(403);
        } else {
            body.setCode(500);
        }
        body.setMessage(cause.getMessage());
        return body;
    }

    public abstract void registerChannel(Channel channel);

    public abstract void unRegisterChannel(Channel channel);

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        log.info("channelUnregistered");
        unRegisterChannel(ctx.channel());
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        log.info("channelRegistered");
        registerChannel(ctx.channel());
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        log.info("channelActive");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        log.info("channelInactive");
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        super.channelReadComplete(ctx);
        log.info("channelReadComplete");
    }

    @Override
    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
        super.channelWritabilityChanged(ctx);
        log.info("channelWritabilityChanged");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
         /*心跳处理*/
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                /*读超时*/
                log.info("READER_IDLE 读超时");
                ctx.channel().close();
//                ctx.disconnect();
            } else if (event.state() == IdleState.WRITER_IDLE) {
                /*写超时*/
                log.info("WRITER_IDLE 写超时");
//                ChannelWrapper channelWrapper=serverRuntimeContext.getProtocolChannelRegistry().get(ctx.channel());
//                if(channelWrapper!=null){
//                    Replies replies=serverRuntimeContext.getMessageGatewayPipeline().messages(channelWrapper.getChannel(),channelWrapper.getEntity());
//                    serverRuntimeContext.getControlServerDeliver().deliver(replies,null);
//                }
//                ctx.channel().writeAndFlush(HEART_STR).sync();
            } else if (event.state() == IdleState.ALL_IDLE) {
                /*总超时*/
                log.info("ALL_IDLE 总超时");
//                ctx.disconnect();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
        log.info("userEventTriggered");
    }



    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        log.info("SERVER接收到消息:" + msg);
        try {
            if (HEART_STR.equals(msg)) {
                ctx.channel().writeAndFlush(HEART_STR).sync();
                return;
            }
            MessageStanza stanza = JSON.parseObject(msg, MessageCommand.class);
            stanza.validate();
            serverRuntimeContext.getWorker().execute(ctx.channel(), stanza);
        } catch (Exception ex) {
            log.error("channelRead0 Exception", ex);
            //to do reply error;
            ex.printStackTrace();
            throw ex;
        }
    }
}
